local Snek = {}

snekSprites = {
	head = lg.newImage("sprites/head.png"),
	headReasting = lg.newImage("sprites/head_reasting.png"),
	tail = lg.newImage("sprites/tail.png"),
}

local TailSegment = {}
function TailSegment:new()
	local ts = {}
	ts.x = 0
	ts.y = 0
	return ts
end

function Snek:new()
	local s = {}
	s.w = 10
	s.h = 10
	s.lastBlock = blocks[10]
	s.x = s.lastBlock.x + s.lastBlock.w / 2
	s.y = s.lastBlock.y - s.h
	s.vy = 0
	s.vx = 0
	s.tail = {}
	s.lives = 3
	s.precisionJumps = 5
	s.doubleJumps = 0
	s.stoneJumps = 0
	--self.doubleJumped = false
	for i = 1, 14 do
		local v = (i % 2 == 0 and s.y) or s.x
		table.insert(s.tail, v)
	end
	s.onGround = false
	setmetatable(s, self)
	self.__index = self
	return s
end

function Snek:update(dt)
	if not self.onGround then
		self.vy = self.vy + dt * 9.5
		self.y = self.y + self.vy
		self.x = self.x + self.vx
	end
	local newVertex = {}
	local up = true
	for i = 1, #self.tail do
		local mult = 0.2
		local v = self.tail[i]
		if i == 1 then
			self.tail[i] = self.x
		elseif i == 2 then
			self.tail[i] = self.y
		else
			self.tail[i] = lerp(v, self.tail[i - 2], mult)
		end
	end
	if self.y > self.lastBlock.y + self.lastBlock.h + 500 then
		self:fall()
	end
end

function Snek:draw()
	lg.setLineWidth(16)
	local green = { 134 / 255, 147 / 255, 70 / 255 }
	local bkgColor = { 45 / 255, 45 / 255, 56 / 255 }
	local offset = 2.2
	local lw = 16
	local a = 0
	local x, y = self.x + 8, self.y
	lg.color(bkgColor)
	lg.setLineWidth(22)
	lg.line(self.tail)
	lg.setLineWidth(16)
	lg.color(green)
	lg.line(self.tail)
	lg.color(1, 1, 1)
	local tailAngle =
		angle(self.tail[#self.tail - 1], self.tail[#self.tail], self.tail[#self.tail - 3], self.tail[#self.tail - 2])
	local scale = 0.33
	lg.draw(snekSprites.tail, self.tail[#self.tail - 1], self.tail[#self.tail], tailAngle, scale, scale, 128, 64)
	if not self.onGround then
		a = angle(self.tail[3], self.tail[4], self.x, self.y)
		x = self.x
	else
		y = self.y + lw / 3
		if dist(self.x, self.y, self.tail[#self.tail - 1], self.tail[#self.tail]) <= 10 then
			local tw, th = lw * 3, lw
			lg.color(bkgColor)
			lg.rectangle(
				"fill",
				self.x - tw / 2 - offset,
				self.y - th - offset,
				tw + offset * 2,
				th + offset * 2,
				th / 2
			)
			lg.color(green)
			lg.rectangle("fill", self.x - tw / 2, self.y - th, tw, th, th / 2)
			y = y - th
		end
		if
			dist(self.x, self.y, self.tail[math.ceil(#self.tail / 2)], self.tail[math.ceil(#self.tail / 2) + 1]) <= 10
		then
			local tw, th = lw * 5, lw
			lg.color(bkgColor)
			lg.rectangle("fill", self.x - tw / 2 - offset, self.y - offset, tw + offset * 2, th + offset * 2, th / 2)
			lg.color(green)
			lg.rectangle("fill", self.x - tw / 2, self.y, tw, th, th / 2)
			y = y - th
		end
	end
	lg.color(1, 1, 1)
	lg.draw(not self.onGround and snekSprites.head or snekSprites.headReasting, x, y, a, 0.35, 0.35, 64, 64)
	lg.setLineWidth(8)
	--lg.circle("fill", self.x, self.y, self.w / 2)
end

function Snek:collideWith(obj, t)
	if t == "block" then
		sfx.land:stop()
		sfx.land:setPitch(love.math.random(90, 110) / 100)
		sfx.land:play()
		if self.y <= obj.y then
			self.vy = 0
			self.y = obj.y - self.h / 2
			self.vx = 0
			self.onGround = true
			if self.lastBlock ~= obj then
				local start_id
				local land_id
				local diff = 0
				for i, b in ipairs(blocks) do
					if b == self.lastBlock then
						start_id = i
					end
					if b == obj then
						land_id = i
					end
				end
				diff = land_id - start_id
				if diff > 0 then
					local addition = diff * diff
					if self.precisionJumps > 0 then
						self.precisionJumps = self.precisionJumps - 1
						if self.x > obj.x + obj.w / 3 and self.x < obj.x + (obj.w / 3) * 2 then
							addition = addition * 2
							sfx.perfect:play()
						end
					end
					score = score + addition
				end
				if score >= nextMilestone then
					self:addLife()
				end
				self.lastBlock = obj
				for i = 0, diff - 1 do
					blocks.shift()
				end
				if fruit.x < self.x - lg:getWidth() then
					fruit:shift()
				end
			end
		elseif self.y >= obj.y + obj.h - 10 then
			self.vy = self.vy > 0 and self.vy or -self.vy
		elseif self.y > obj.y and self.y < obj.y + obj.h then
			self.vx = -self.vx
		end
	elseif t == "fruit" then
		sfx.fruit:play()
		if obj.subtype == "precision" then
			self.precisionJumps = self.precisionJumps + 5
		elseif obj.subtype == "double" then
			self.doubleJumps = self.doubleJumps + 3
		elseif obj.subtype == "stone" then
			self.stoneJumps = self.stoneJumps + 3
		end
		obj:shift()
	end
end

function Snek:jump(vx, vy, power)
	if self.onGround or self.doubleJumps > 0 then
		--local mult = 10
		self.vy = vy * power
		self.vx = vx * power
		sfx.jump:setPitch(power / 10)
		sfx.jump:play()
		if not self.onGround and self.doubleJumps > 0 then
			self.doubleJumps = self.doubleJumps - 1
		end
		self.onGround = false
	end
end

function Snek:fall()
	if self.lives > 0 then
		sfx.fall:play()
		self.x = self.lastBlock.x + self.lastBlock.w / 2 - self.w
		self.y = self.lastBlock.y - self.h
		if score > 0 then
			self.lives = self.lives - 1
		end
		for i = 1, #self.tail do
			local ts = self.tail[i]
			if i == 1 then
				self.tail[i] = self.x
			elseif i == 2 then
				self.tail[i] = self.y
			else
				self.tail[i] = self.tail[i - 2]
			end
		end
	else
		sfx.death:play()
		if score > highScore then
			highScore = score
			love.filesystem.write("save.txt", tostring(highScore))
		end
		score = 0
		state = STATES.MENU
		music.menu:seek(music.game:tell())
		music.game:stop()
		music.menu:play()
	end
end

function Snek:stop()
	self.vx = 0
	self.vy = 10
	self.stoneJumps = self.stoneJumps - 1
end

function Snek:addLife()
	self.lives = self.lives + 1
	nextMilestone = nextMilestone + milestoneStep
	if score >= nextMilestone then
		self:addLife()
	end
end

return Snek
